﻿using LuaInterface;

namespace Framework
{
    public sealed class GeneralCallBackWithParam : SLICacheable
    {
        private static readonly SLObjectPool<GeneralCallBackWithParam> CbPool = new SLObjectPool<GeneralCallBackWithParam>(256);

        public static void GetOrReuse(ref GeneralCallBackWithParam cb, System.Action<object> csharpCb, LuaFunction luaCb, LuaTable luaObj, object param)
        {
            if (cb == null)
            {
                cb = CbPool.GetObject();
            }
            cb._Reuse(csharpCb, luaCb, luaObj, param);
        }

        public static void GetOrReuse(ref GeneralCallBackWithParam cb, System.Action<object> csharpCb, object param)
        {
            if (cb == null)
            {
                cb = CbPool.GetObject();
            }
            cb._Reuse(csharpCb, null, null, param);
        }

        public static void GetOrReuse(ref GeneralCallBackWithParam cb, LuaFunction luaCb, LuaTable luaObj, object param)
        {
            if (cb == null)
            {
                cb = CbPool.GetObject();
            }
            cb._Reuse(null, luaCb, luaObj, param);
        }

        public static void RecycleInst(ref GeneralCallBackWithParam callBack)
        {
            if (null == callBack)
            {
                return;
            }
            CbPool.PutObject(callBack);
            callBack = null;
        }

        public static void Invoke(ref GeneralCallBackWithParam gcb, params object[] args)
        {
            if (null != gcb)
            {
                if (args == null || 0 == args.Length)
                {
                    gcb.DoCallBack();
                    return;
                }
                gcb.DoLuaCallBackWithArgs(args);
            }
        }

        public static void InvokeAndRecycle(ref GeneralCallBackWithParam gcb, params object[] args)
        {
            if (null != gcb)
            {
                Invoke(ref gcb, args);
                RecycleInst(ref gcb);
            }
        }
        public static void Clear()
        {
            Logger.Log("GeneralCallBackWithParam.Clear(), CbPool count = " + CbPool.CurCount);
            CbPool.Clear();
        }

        private System.Action<object> _csharpCb;
        private LuaFunction _luaCb;
        private LuaTable _luaObj;
        private object _param;

        /// <summary>
        /// 重设这个通用回调里面参数，用来重用
        /// </summary>
        /// <param name="csharpCb">没有传null</param>
        /// <param name="luaCb">没有传null</param>
        /// <param name="luaObj">没有传null</param>
        /// <param name="param">参数</param>
        private void _Reuse(System.Action<object> csharpCb, LuaFunction luaCb, LuaTable luaObj, object param)
        {
            this._csharpCb = csharpCb;
            this._luaCb = luaCb;
            this._luaObj = luaObj;
            this._param = param;
        }

        /// <summary>
        /// 判断lua回调是否一样，可以用来判断防止多次加回调
        /// </summary>
        /// <param name="luaCb"></param>
        /// <param name="luaObj"></param>
        /// <returns></returns>
        public bool IsEqual(LuaFunction luaCb, LuaTable luaObj)
        {
            if (luaCb != null)
            {
                if (luaObj != null)
                {
                    return luaCb == _luaCb && luaObj == _luaObj;
                }
                return luaCb == _luaCb;
            }
            return false;
        }

        private void DoCallBack()
        {
            if (null != _csharpCb)
            {
                try
                {
                    _csharpCb(_param);
                }
                catch (System.Exception exp)
                {
                    Logger.LogException(exp);
                }
            }
            if (null == _luaCb) return;
            try
            {
                if (null != _luaObj)
                {
                    _luaCb.Call(_luaObj, _param);
                }
                else
                {
                    _luaCb.Call(_param);
                }
            }
            catch (System.Exception exp)
            {
                Logger.LogException(exp);
            }
        }

        private void DoLuaCallBackWithArgs(params object[] args)
        {
            if (null == _luaCb) return;
            try
            {
                //外部调用PCall，会有置空luaCb操作，报警告：Lua stack top is 1
                _luaCb.Call(_luaObj, _param, args);
            }
            catch (System.Exception exp)
            {
                Logger.LogException(exp);
            }
        }

        public void Reset()
        {
            _csharpCb = null;
            _luaCb = null;
            _luaObj = null;
            _param = null;
        }
    }
}

